﻿using AutoRegistDependency.Attributes;
using Lextm.SharpSnmpLib;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Core.Helper
{
    [Component]
    public class IpHelper
    {

        public bool ValidateIPAddress(string ipAddress)
        {
            Regex validipregex = new Regex(@"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
            return (ipAddress != "" && validipregex.IsMatch(ipAddress.Trim())) ? true : false;
        }


        /// <summary>
        /// 验证ip字符串并对成功的ip地址进行操作
        /// </summary>
        /// <typeparam name="T">方法返回的泛型类型</typeparam>
        /// <param name="ip">ip字符串</param>
        /// <param name="ipFunc">后续对ip的操作</param>
        /// <returns>委托返回的值</returns>
        /// <exception cref="ArgumentException">非ip字符串将抛出异常</exception>
        private T ValidateIp<T>(string ip,Func<IPAddress,T> ipFunc)
        {
            if(IPAddress.TryParse(ip, out IPAddress? ipAddress))
            {
                return ipFunc(ipAddress);
            }
            else
            {
                throw new ArgumentException($"ip is not correct!");
            }
        }
        /// <summary>
        /// 将ip转为无符号32位数字
        /// </summary>
        /// <param name="ip">ip字符串</param>
        /// <returns>无符号32位数字</returns>
        public uint IpToUInt(string ip)
        {
            return IpToNumber(ip, bytes => BitConverter.ToUInt32(bytes.Reverse().ToArray()));
        }
        /// <summary>
        /// 将ip转为无符号32位数字
        /// </summary>
        /// <param name="ip">ip字符串</param>
        /// <returns>无符号32位数字</returns>
        public uint IpToUInt(IPAddress ip)
        {
            return IpToNumber(ip, bytes => BitConverter.ToUInt32(bytes.Reverse().ToArray()));
        }
        /// <summary>
        /// 将无符号32位数字转为ip地址
        /// </summary>
        /// <param name="ip">32位无符号数字</param>
        /// <returns>ip地址</returns>
        public IPAddress UintToIp(uint ip)
        {
            var bytes=BitConverter.GetBytes(ip);
            return new IPAddress(bytes.Reverse().ToArray());
        }
        /// <summary>
        /// 将无符号32位数字转为ip字符串
        /// </summary>
        /// <param name="ip">32位无符号数字</param>
        /// <returns>ip字符串</returns>
        public string UintToIpString(uint ip)
        {
            var ipAddress = UintToIp(ip);
            return ipAddress.ToString();
        }
        /// <summary>
        /// 将ip字符串转为64位数字
        /// </summary>
        /// <param name="ip">ip字符串</param>
        /// <returns>64位ip数字</returns>
        public long IpToLong(string ip)
        {
            return ValidateIp(ip, ipAddress =>
            {
                var appendBytes = new byte[4];
                var longBytes = ipAddress.GetAddressBytes().Reverse().Concat(appendBytes).ToArray();
                return BitConverter.ToInt64(longBytes);
            });
        }
        /// <summary>
        /// 将ip字符串转为64位数字
        /// </summary>
        /// <param name="ip">ip</param>
        /// <returns>64位数字</returns>
        public long IpToLong(IPAddress ip)
        {
            return IpToNumber(ip, bytes => BitConverter.ToInt64(bytes.Reverse().ToArray()));
        }
        /// <summary>
        /// 64位数字转成ip字符串
        /// </summary>
        /// <param name="ip">ip地址</param>
        /// <returns>ip字符串</returns>
        public string LongToIpString(long ip)
        {
            var bytes = BitConverter.GetBytes(ip)[0..4].Reverse().ToArray();
            return new IPAddress(bytes).ToString();
        }
        /// <summary>
        /// 获取连续的iplist
        /// </summary>
        /// <param name="startIp">起始ip</param>
        /// <param name="ipCount">需要多少个ip(包含起始ip)</param>
        /// <param name="step">每个ip之间的步长</param>
        /// <param name="UnexpectionIp">若传入此值，返回true的ip将会被舍弃</param>
        /// <returns></returns>
        public List<IPAddress> GetContinuousIP(IPAddress startIp,int ipCount,uint step, Func<IPAddress,bool>? unexpectionIp = null)
        {
            List<IPAddress> result = [startIp];
            uint intStartIp = IpToUInt(startIp);
            while (result.Count <= ipCount)
            {
                intStartIp += step;
                IPAddress ip = UintToIp(intStartIp);
                if (unexpectionIp != null)
                {
                    if (unexpectionIp(ip))
                    {
                        continue;
                    }
                }
                result.Add(ip);
            }
            return result;
        }
        /// <summary>
        /// 获取连续的iplist
        /// </summary>
        /// <param name="startIp">起始ip</param>
        /// <param name="ipCount">需要多少个ip(包含起始ip)</param>
        /// <param name="step">每个ip之间的步长</param>
        /// <param name="unexpectionIp">若传入此值，返回true的ip将会被舍弃</param>
        /// <returns></returns>
        public List<string> GetContinuousIP(string startIp, int ipCount, uint step, Func<IPAddress,bool>? unexpectionIp = null)
        {
            return ValidateIp(startIp, ipAddress =>
            {
                List<IPAddress> iPAddresses = GetContinuousIP(ipAddress, ipCount, step, unexpectionIp);
                return iPAddresses.Select(t => t.ToString()).ToList();
            });

        }
        /// <summary>
        /// 获取两个ip之间的连续ip
        /// </summary>
        /// <param name="startIp">起始ip</param>
        /// <param name="endIp">结束ip</param>
        /// <param name="unexpectionIp">若传入此值，返回true的ip将会被舍弃</param>
        /// <returns>两个ip之间所有的ip</returns>
        public List<IPAddress> GetIntervalIP(IPAddress startIp,IPAddress endIp, Func<IPAddress,bool>? unexpectionIp = null)
        {
            List<IPAddress> result= [];
            uint start=IpToUInt(startIp);
            uint end=IpToUInt(endIp);
            while(start<= end)
            {
                IPAddress ip=UintToIp(start);
                start++;
                if (unexpectionIp != null)
                {
                    if (unexpectionIp(ip))
                    {
                        continue;
                    }
                }
                result.Add(ip);
            }
            return result;
        }
        /// <summary>
        /// 获取两个ip之间的连续ip
        /// </summary>
        /// <param name="startIp">起始ip</param>
        /// <param name="endIp">结束ip</param>
        /// <param name="unexpectionIp">若传入此值，返回true的ip将会被舍弃</param>
        /// <returns>两个ip之间所有的ip</returns>
        public List<string> GetIntervalIP(string startIp, string endIp, Func<IPAddress,bool>? unexpectionIp = null)
        {
            return ValidateIp(startIp, startIpAddress => ValidateIp(endIp, endIpAddress => GetIntervalIP(startIpAddress, endIpAddress, unexpectionIp).Select(t=>t.ToString()).ToList()));
        }
        /// <summary>
        /// 获取ip的种类
        /// </summary>
        /// <param name="ip">ip地址</param>
        /// <returns>0为A类，1为B类，2为C类...以此类推</returns>
        public int GetIpType(IPAddress ip)
        {
            byte[] ipBytes=ip.GetAddressBytes();
            byte firstByte = ipBytes[0];
            int index = 0;
            while (index <= 7)
            {
                if (!GetBitInByte(firstByte, index))
                {
                    break;
                }
                index++;
            }
            return index;
        }
        /// <summary>
        /// 获取ip的种类
        /// </summary>
        /// <param name="ip">ip地址</param>
        /// <returns>0为A类，1为B类，2为C类...以此类推</returns>
        public int GetIpType(string ip)
        {
            return ValidateIp(ip, ipAdress => GetIpType(ipAdress));
        }

        /// <summary>
        /// 获取字节中某一位的值
        /// </summary>
        /// <param name="data"></param>
        /// <param name="index">从左到右 高位在前低位在后 0-7</param>
        /// <returns></returns>
        public bool GetBitInByte(byte data, int index)
        {
            if(!(index>=0 && index <= 7))
            {
                throw new ArgumentException("index must between 0 and 7!!");
            }
            return (data & (byte)Math.Pow(2, 7-index)) > 0;
        }
        /// <summary>
        /// ip字符串转成数字
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ip">ip字符串</param>
        /// <param name="ipFunc">ip转化方法</param>
        /// <returns>目标数字</returns>
        public T IpToNumber<T>(string ip, Func<byte[], T> ipFunc)
        {
            return ValidateIp(ip, ipAddress =>
            {
                var bytes = ipAddress.GetAddressBytes();
                return ipFunc.Invoke(bytes);
            });
        }
        /// <summary>
        /// ip地址转成目标类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ip">ip地址</param>
        /// <param name="ipFunc">转化方法</param>
        /// <returns></returns>
        public T IpToNumber<T>(IPAddress ip, Func<byte[], T> ipFunc)
        {
            byte[] bytes=ip.GetAddressBytes();
            return ipFunc.Invoke(bytes);
        }
        /// <summary>
        /// 是否是子网掩码
        /// </summary>
        /// <param name="netmask">子网掩码字符串</param>
        /// <returns></returns>
        public bool IsNetMask(string netmask)
        {
            return ValidateIp(netmask, ipAddress =>
            {
                bool isZero = false;
                var ipBytes = ipAddress.GetAddressBytes();
                foreach (var b in ipBytes)
                {
                    int index = 0;
                    while (!isZero && index <= 7)
                    {
                        isZero = !GetBitInByte(b, index);
                        index++;
                    }
                    while (isZero && index <= 7)
                    {
                        if (GetBitInByte(b, index))
                        {
                            return false;
                        }
                        index++;
                    }
                }
                return true;
            });
        }
    }
}
